package cn.sciento.transfer.infra.datasource.ddl;

import cn.sciento.core.exception.CommonException;import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import cn.sciento.core.util.FieldNameUtils;
import org.springframework.util.Assert;

public class OracleTableScriptBuilder extends BaseTableScriptBuilder {
  public static final String CREATE_TABLE = "script";
  
  public String getCreateTableScript(Connection connection, String tableName) throws SQLException {
    String sql = String.format(" SELECT to_char(DBMS_METADATA.GET_DDL('TABLE','%s')) AS script FROM DUAL ", new Object[] { tableName });
    List<Map<String, Object>> mapList = doQuery(connection, sql, Boolean.valueOf(true));
    Assert.isTrue(CollectionUtils.isNotEmpty(mapList), "error.data_not_exists");
    return (String)((Map)mapList.get(0)).get("script");
  }
  
  public List<String> getTablePrimaryKey(Connection connection, String schemaName, String tableName) throws SQLException {
    String sql = String.format("SELECT%n\tai.index_name,%n\tuic.column_name%n%nFROM%n\tALL_INDEXES ai LEFT JOIN user_ind_columns uic ON ai.index_name = uic.index_name%nWHERE%nai.uniqueness='UNIQUE' %n\tAND ai.OWNER = '%s'%n\tAND ai.table_name = '%s'", new Object[] { schemaName, tableName });
    List<Map<String, Object>> mapList = doQuery(connection, sql, Boolean.valueOf(true));
    if (CollectionUtils.isEmpty(mapList))
      throw new CommonException("can not find either of primaryKey and uniqueKey from table:" + tableName);
    List<String> primaryKeys = findPrimaryKey(mapList);
    if (CollectionUtils.isEmpty(primaryKeys))
      throw new CommonException("can not find either of primaryKey and uniqueKey from table:" + tableName);
    return primaryKeys;
  }
  
  private List<String> findPrimaryKey(List<Map<String, Object>> mapList) {
    if (mapList.size() == 1)
      return buildPrimaryKey(mapList); 
    Map<String, List<Map<String, Object>>> indexNameMap = (Map<String, List<Map<String, Object>>>)mapList.stream().collect(Collectors.groupingBy(item -> (String)item.get("indexName")));
    for (String indexName : indexNameMap.keySet()) {
      if (indexName.startsWith("PK") || indexName.startsWith("pk"))
        return buildPrimaryKey(indexNameMap.get(indexName)); 
    } 
    return buildPrimaryKey(indexNameMap.values().stream().findFirst().get());
  }
  
  private List<String> buildPrimaryKey(List<Map<String, Object>> indexMapList) {
    List<String> primaryKeys = new ArrayList<>(indexMapList.size());
    for (Map<String, Object> indexMap : indexMapList) {
      String columnName = FieldNameUtils.underline2Camel(((String)indexMap.get("columnName")).toLowerCase(), true);
      primaryKeys.add(columnName);
    } 
    return primaryKeys;
  }
}
